﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
using System.Linq;
using DBSchemaViewer.BackEnd.Entities;
using DBSchemaViewer.BackEnd.ModelXML;
using DBSchemaViewer.BackEnd.Entities.MetaEntities;
using DBSchemaViewer.BackEnd.CommonHelpers;
using DBSchemaViewer.Business.Controller.Messages;
using DBSchemaViewer.Business.Controller.IViews;
using DBSchemaViewer.Business.Controller.Helpers;

namespace DBSchemaViewer.Business.Controller
{
    /// <summary>
    /// 
    /// </summary>
    public partial class ControllerRunner        
    {
        IViewMainPage _mainPage;       

        public ControllerRunner()
        {            
        }


        /// <summary>
        /// Main page view, most of the operations will use this interface
        /// 
        /// </summary>
        public void AddView(IViewMainPage IMainpage)
        {
            _mainPage = IMainpage;
        }


        /// <summary>
        /// Generate an empty entity and ask the view to show and addTableDlg.
        /// Once the View is done (user added the fields and clicked ok) it 
        /// will perform another RunCommand to ask the controller to add the 
        /// table to the repository and do whatever is needed to update the layout.
        /// </summary>
        public void RunCommand(IViewBase sender, MsgBase message)
        {            
            switch (message.MessageType_info)
            {
                // Create new document
                case MessageType.DOCUMENTOP_CreateNewDocument:
                    CreateNewDocument();
                break;


                case MessageType.TABLEOP_UpdateTableCanvasPosition:
                    UpdateTablePosition(message);
                break;

                case MessageType.DOCUMENTOP_LoadStringXMLContentIntoDiagram:
                    LoadXMLContentIntoDiagram(message);
                break;

            }
        }

        
        
        private void LoadXMLContentIntoDiagram(MsgBase message)
        {
            MsgLoadStringContentIntoDiag theMessage = message as MsgLoadStringContentIntoDiag;

            if(theMessage != null)
            {
               LoadRawStringContentIntoXMLDiagramMemoryStructure(theMessage.xmlContent);
            }
        }


        

        /// <summary>
        /// Once we load the string (that contains the diagram XML to work with) whether from local storage 
        /// or from a remote service, we just call this common method (load the XML into the entities 
        /// structures)
        /// </summary>
        /// <param name="fileContent"></param>
        private void LoadRawStringContentIntoXMLDiagramMemoryStructure(string fileContent)
        {
            // Wipe current document
            CreateNewDocument();
            
            // XML            
            DocumentDAL documentDAL = new DocumentDAL();

            documentDAL.LoadDocument(fileContent);

            TableDAL tableDAL = new TableDAL();
            RelationDAL relationDAL = new RelationDAL();

            EntityTable[] tables = tableDAL.GetTables();
            EntityRelation[] relations = relationDAL.GetRelations();

            // TODO: Set canvas size, etc..
            // TODO: Implement EntityRelations Get Relations
            // 0. Setup the global properties 
            // Canvas widht, height...
            // Last ID seed must be already there, because we read it from the model??

            // 1. Create Tables UI
            foreach (EntityTable currTable in tables)
            {
                _mainPage.CreateTableControl(currTable);
            }

            // 2. Create Relations UI
            foreach (EntityRelation currRelation in relations)
            {
                _mainPage.CreateRelationControl(currRelation);
            }

            
            _mainPage.RefreshMainCanvas();

            // Set the canvas size to the just loaded size indicated on the XML
            MetadataDAL metadataDAL = new MetadataDAL();

            EntityDocumentSettings documentSettings = metadataDAL.RetrieveDocumentSettings();
            _mainPage.UpdateCanvasSize(documentSettings.CanvasSize);            
             
        }


        protected void CreateNewDocument()
        {
            // 1. Wipe all the UI content (list of and controls by them selves.
            // 2. Create a new document from the datastore.
            // 3. Redraw the UI with the new content: here we should pass by param
            //       - Metadata (canvas size, scale).
            //       - Tables.
            //       - Relations
            _mainPage.WipeAllTheDiagramUIControls();
            _mainPage.ResetSelectedControl();
            DocumentDAL documentDAL = new DocumentDAL();
            documentDAL.NewDocument();
            // TODO: Refresh UI 
        }


        protected EntityTable AddNewTableUserInterface()
        {
            EntityTable table = new EntityTable();
            table.Name = "";
            table.Fields = new EntityTableFieldEntries();

            return table;
        }



        /// <summary>
        /// Just update the table position on the data model (when the user drags and drop a table
        /// this change must be reflected on the data model, on the UI is directly updated).
        /// </summary>
        /// <param name="message"></param>
        private void UpdateTablePosition(MsgBase message)
        {
            MsgUpdateTableCanvasPosition msgUpdatePosition = message as MsgUpdateTableCanvasPosition;

            TableDAL tableDAL = new TableDAL();

            tableDAL.UpdateTableCanvasPosition(msgUpdatePosition.tableID, msgUpdatePosition.newPosition);

            // For the sake of performance the control position is updated directly on the UI (by dragging and 
            // dropping).

            // BUT we must update the relations that are surroinding the moved table object
            // Let's ask using the 
            RelationDAL relationDAL = new RelationDAL();

            EntityRelations entityRelations = relationDAL.GetRelationsByTableID(msgUpdatePosition.tableID);

            foreach (EntityRelation currRelation in entityRelations)
            {
                _mainPage.UpdateRelationControlCanvasPosition(currRelation);
            }            
        }


        /// <summary>
        /// Single entry point, this mehtod is in use when removing one relation and one
        /// removing a table (delete all direct connected table relations).
        /// </summary>
        /// <param name="relationID"></param>
        private void RemoveRelation(int relationID)
        {
            RelationDAL relationDAL = new RelationDAL();
            
            // 2. Find table fields affected by FK
            // this method will return the ID's of the fields that are affected in the destination table
            // Think if it would be a good idea to return the table ID as well?
            EntityRelation relationToRemove = relationDAL.GetRelationByRelationID(relationID);

            // Check in the TO fields, if the relation has more than one FK:
            //   - Only this FK: change in the table for that field the FK bool to false
            //             --> In the entity
            //             --> In the entities stored in the controls (that's a bit of overhead :-(). But
            //                 I still think this would help to make the application respond faster.
            //
            foreach (EntityRelationField currRelationField in relationToRemove.RelationFields)
            {
                // FK Candidate
                int fkInternalID = currRelationField.FieldDestination;

                // Count Fine working
                int numberOfFKDestinations = relationDAL.CountNumberOfFKRelationDestinationsASingleFieldHas(fkInternalID);


                // 4. If the Table Field has no more FK associations, update the XML model (no FK)
                if (numberOfFKDestinations == 1)
                {
                    int tableInternalIDToUpdate = relationToRemove.TableDestinationID;

                    TableDAL tableDAL = new TableDAL();

                    EntityTableFieldEntry currentField = tableDAL.GetTableField(tableInternalIDToUpdate, fkInternalID);

                    currentField.IsForeignKey = false;


                    // 5. If the Table Field has no more FK associations, update the XML model (no FK)
                    tableDAL.UpdateTableField(tableInternalIDToUpdate, currentField);

                    EntityTable modifiedTable = tableDAL.GetTable(tableInternalIDToUpdate);

                    // TODO !!!!
                    // 6. If the Table Field has no more FK associations, update the control indicating that now is no FK   
                    _mainPage.UpdateTableEntityOnControlButNotUI(modifiedTable);

                }
            }


            // 7. Remove the relation form the XML model.
            relationDAL.DeleteRelation(relationID);


            // 8. Propage the change to the UI (remove relation control)
            _mainPage.RemoveRelationControl(relationID);
        }

        
    }
}
